﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;

using Bling.Core;
using Bling.WPF;
using Bling.WPF.Util;
using Bling.Slides;
using Bling.Util;
using Bling.Shaders;
using Bling.Graphics;
using Bling.Angles;

namespace Bling.Example {
  using Bling.Matrices;
  using Bling.WPF3D;
  using Bling.WPF.Custom;
  using Bling.DX;
  using Bling.Reactive;
  public class ListManager : Canvas {
    private readonly List<TextBoxBl> Labels = new List<TextBoxBl>();
    private int Counter = 0;
    private IntBl Selected;
    public ListManager(CanvasBl Canvas) {
      this.Bl().PanelParent = Canvas;
      this.Bl().Height = 0d;
      Selected = this.Property(-1.Bl());
      Unselect = IntBl.Assign(Selected, -1);
    }
    public readonly Action Unselect;

    public void AddAction(Action A) {
      var PermId = Labels.Count;
      var lbl = new TextBoxBl(this) {
        Font = { Brush = (Selected == PermId).Condition(Brushes.Red, Brushes.White.Bl()), Weight = FontWeights.SemiBold },
        Background = Brushes.Transparent,
        //IsReadOnly = true, 
        MaxLines = 1, Width = this.Bl().Width, Left = 0d,
        Text = "Action-" + Counter,

      };
      Counter += 1;
      var cover = new CanvasBl((CanvasBl)this) {
        Size = lbl.Size, LeftTop = lbl.LeftTop,
        Background = Brushes.Transparent,
      };
      lbl.Top = (PermId) * lbl.Height;
      this.Bl().Height = PermId * lbl.Height;
      Labels.Add(lbl);

      { // on tap, goto there.
        Selected[cover.Mouse.Click] = PermId;
        new Command("A", A)[cover.Mouse.Click].Forever.Apply();
      }
      cover.Mouse.HoldTimeout = TimeSpan.FromMilliseconds(400);
      { // on hold
        lbl.Keys.Focus.Acquire[cover.Mouse.Hold.In].Forever.Apply();
        lbl.SelectAll[cover.Mouse.Hold.In].Forever.Apply();
      }
      var Pos = this.Bl().Mouse.Position;
      { // on drag. redo this later!
        var CurrentIndex = Labels.IndexOf(lbl);
        var bias = 0d; // (Pos.Y - (CurrentIndex * lbl.Height)).Now;
        var GetIndex = ((IntBl)((Pos.Y - bias) / lbl.Height)).AsFunc;
        cover.Mouse.Drag.Update.SubscribeForever(() => {
          var AtIndex0 = GetIndex();
          var AtIndex = AtIndex0;
          AtIndex = Math.Max(AtIndex, 0);
          AtIndex = Math.Min(AtIndex, Labels.Count - 1);
          CurrentIndex = Labels.IndexOf(lbl.CurrentValue);
          if (AtIndex != CurrentIndex) {
            Labels.RemoveAt(CurrentIndex); // this is self.
            if (AtIndex < CurrentIndex) {
              Labels.Insert(AtIndex, lbl.CurrentValue);
              for (int i = AtIndex; i < Labels.Count; i++)
                Labels[i].Top = i * Labels[i].Height;
            } else {
              Labels.Insert(AtIndex, lbl.CurrentValue);
              for (int i = CurrentIndex; i < Labels.Count; i++)
                Labels[i].Top = i * Labels[i].Height;

            }
          }
        });
      }
    }
  }
  public class FakeVolume : HasDX10Canvas {

    private Double2Bl CutEndFor(Double2Bl CutSlope, Double2Bl CutStart) {
      var p = new Double2Bl(CutSlope.X.Sign, CutSlope.Y.Sign);
      p = (p + 1d).Min(1d);
      var t = (p - CutStart) / CutSlope;
      return CutStart + t.X.Min(t.Y) * CutSlope;
    }
    public static readonly Double2Bl BufferSize = new Double2Bl(0, 0);
    public static readonly Double2Bl ViewportSize = new Double2Bl(500, 500) + BufferSize;
    private enum MouseMode {
      Rotate, Pan, Zoom
    }


    public FakeVolume()
      : base(true) {
      CanvasBl Canvas = this;
      Host.Size = ViewportSize - BufferSize;
      Host.CenterBottom = new Double2Bl(Canvas.CenterSize.X, Canvas.Height);
      OverlayContent.Background = new ColorBl(1, 1, 1, .01);

      Canvas.Background = Brushes.Black;
      // properties.
      //var RotateA = this.Property(QuaternionBl.Identity);

      var AtCut = this.Property(QuaternionBl.Identity);
      //var AtCutInverse = //this.Property
      //  (AtCut.Invert /*.Matrix*/);

      var CutStart = this.Property(new Double2Bl(0, .5));
      var CutSlope = this.Property(new Double2Bl(1, 0).Normalize);
      var Pan = this.Property(Double2Bl.Default);
      var Zoom = this.Property(1d.Bl());
      DoubleBl[] MaterialScales = new DoubleBl[MaterialColors.Length];
      for (int i = 0; i < MaterialColors.Length; i++) MaterialScales[i] = this.Property(1d.Bl());
      QuaternionBl WorldRotate = this.Property(QuaternionBl.Identity);

      // derived.
      DoubleBl CutSlide, CutAngle;
      var CutEnd = CutEndFor(CutSlope, CutStart);
      Action ResetCutSlide = () => { };
      {
        var CutSlideSlider = new SliderBl(Canvas) {
          CenterBottom = Host.CenterTop,
          Width = Host.Width,
          Minimum = 0,
          Maximum = 1,
          Value = 0,
        };
        CutSlide = CutSlideSlider;
        new LabelBl(Canvas) {
          RightCenter = CutSlideSlider.LeftCenter,
          Font = { Brush = Brushes.White, Weight = FontWeights.SemiBold, },
          Content = "Slide",
          Visibility = CutSlideSlider.Visibility,
        };
        // first, create some sliders to control the simulation.
        var CutAngleSlider = new SliderBl(Canvas) {
          CenterBottom = CutSlideSlider.CenterTop,
          Width = Host.Width,
          Minimum = 0.01,
          Maximum = 1,
          Value = 0.01
        };
        CutAngle = CutAngleSlider;
        var AllSaveProperties = new Brand[] {
          WorldRotate, AtCut, CutStart, CutSlope, Pan, Zoom, CutAngle
        };

        new LabelBl(Canvas) {
          RightCenter = CutAngleSlider.LeftCenter,
          Font = { Brush = Brushes.White, Weight = FontWeights.SemiBold, },
          Content = "Angle",
          Visibility = CutAngleSlider.Visibility,
        };

        var Waypoints = new ListManager(Canvas);
        {
          Waypoints.Bl().LeftTop = Host.RightTop;
          Waypoints.Bl().Width = 100d;
        }
        var SaveRestore = this.Property(DoubleBl.Default);

        ButtonBl Save = new ButtonBl(Canvas) {
          LeftBottom = Host.RightTop,
          Content = "Save Position",
          Width = 100,
          Click = () => {
            var SavePoint = new WayPoint(AllSaveProperties);
            Action a = () => {
              SavePoint.Restore(SaveRestore.Ease.Cubic.InOut);
              SaveRestore.Stop(false);
              SaveRestore.Now = 0d;
              SaveRestore.Animate().Duration(1000d).Completed((d) => ResetCutSlide()).To = 1d;
            };
            Waypoints.AddAction(a);
          },
        };

        {
          // sliders
          var ScaleSlider = new SliderBl(Canvas) {
            LeftBottom = CutAngleSlider.LeftTop,
            Width = CutAngleSlider.Width,
            Minimum = 0,
            Maximum = 1d,
            Value = MaterialScales[0],
          };
          MaterialScales[0].Bind = ScaleSlider.Value;
          new LabelBl(Canvas) {
            RightCenter = ScaleSlider.LeftCenter,
            Font = { Brush = Brushes.White, Weight = FontWeights.SemiBold },
            Content = "Transfer",
          };

          RectangleBl[] Outers = new RectangleBl[MaterialColors.Length];
          var Pos = ScaleSlider.LeftTop;
          IntBl SelectedScale = this.Property(0.Bl());
          for (int i = 0; i < MaterialColors.Length; i++) {
            var i0 = i;
            Outers[i0] = new RectangleBl(Canvas) {
              Size = 22,
              ZIndex = 0,
              Fill = (i0 == SelectedScale).Condition(Brushes.White.Bl(), Brushes.DarkGray),
              Stroke = { Brush = Brushes.Transparent, Thickness = 1d },
              LeftBottom = Pos,
            };
            { // a bit ugly.
              MaterialScales.Table(SelectedScale)[Outers[i0].Mouse.Down] = MaterialScales.Table(SelectedScale);
              SelectedScale[Outers[i0].Mouse.Down] = i0;
              ScaleSlider.Value[Outers[i0].Mouse.Down] = MaterialScales[i0];
              MaterialScales[i0][Outers[i0].Mouse.Down].Bind = ScaleSlider.Value;
            }
            new RectangleBl(Canvas) {
              Size = 9 + 9 * MaterialScales[i0],
              ZIndex = 1,
              IsHitTestVisible = false,
              Fill = MaterialColors[i0],
              CenterPosition = Outers[i0].CenterPosition,
            };
            Pos = Outers[i0].RightBottom;
          }
        }
      }
      {
        {
          var CutRect = new RectangleBl(OverlayContent) {
            LeftTop = 0d,
            Size = OverlayContent.Size,
            Stroke = { Brush = Brushes.White, Thickness = 6d, },
            Opacity = 0.3,
            ZIndex = 4,
          };
          {
            {
              CutAngle[CutRect.Mouse.Drag.In] = CutAngle.Max(.1d);
              AtCut[CutRect.Mouse.Drag.In] = WorldRotate;
            }
            Double2Bl MouseAt = OverlayContent.Mouse.Position;
            {
              var Start = MouseAt[CutRect.Mouse.Drag.In] / ViewportSize;
              var End = MouseAt / ViewportSize; // where we are now.

              Start += Pan / new Double2Bl(-2d, +2d);
              End += Pan / new Double2Bl(-2d, +2d);

              Start = Start * 2d - 1d;
              End = End * 2d - 1d;
              Start = Start / Zoom;
              End = End / Zoom;
              Start = (Start + 1d) / 2d;
              End = (End + 1d) / 2d;

              var NewCutSlope = (End - Start).Normalize;
              var Target = (new Double2Bl(NewCutSlope.X.Sign, NewCutSlope.Y.Sign));
              Target = (Target + 1d).Min(1d);
              Target = 1d - Target;
              var UseSlope = NewCutSlope * -1d; // look backward.
              var t = (Target - Start) / UseSlope;
              var pX = Start + t.X * UseSlope;
              var pY = Start + t.Y * UseSlope;
              var NewCutStart = (t.X < t.Y).Condition(pX, pY);

              CutStart[CutRect.Mouse.Drag.Update] = NewCutStart;
              CutSlope[CutRect.Mouse.Drag.Update] = NewCutSlope;
            }

            {
              BoolBl StartIsX = CutStart.X > 0 & CutStart.X < 1;
              //BoolBl EndIsX = CutEnd.X > 0 & CutEnd.X < 1;

              var StartRatio = CutStart[StartIsX.Condition(0, 1)];
                //var EndRatio = CutStart[StartIsX.Condition(0, 1)];
                //var Average = (StartRatio + EndRatio) / 2d;
                CutSlide[CutRect.Mouse.Drag.Out] = StartRatio;

              Double2Bl OldCutStart = CutStart[CutRect.Mouse.Drag.Out];
              Double2Bl NewCutStart =
                (StartIsX[CutRect.Mouse.Drag.Out]).Condition(new Double2Bl(CutSlide, OldCutStart.Y),
                                                              new Double2Bl(OldCutStart.X, CutSlide));

              CutStart[CutRect.Mouse.Drag.Out].Bind = NewCutStart;
            }
          }
        }
      }
      DoubleBl SphereDiameter = 400d;
      EllipseBl sphere = new EllipseBl(OverlayContent) {
        Size = SphereDiameter,
        CenterPosition = OverlayContent.CenterSize,
        Fill = new ColorBl(1, 1, 1, 0.01),
        ZIndex = 10,
        Stroke = { Brush = Brushes.White, Thickness = 0 },
        IsHitTestVisible = false
      };
      {
        var MouseAt = sphere.Mouse.Position / sphere.Size;
        MouseAt = MouseAt * 2d - 1d;
        MouseAt = MouseAt * new Double2Bl(-1d, +1d); // flip X
        {
          var MouseAt3D = new Double3Bl(MouseAt, (1d - MouseAt.LengthSquared).Max(0d).Sqrt);
          MouseAt3D = MouseAt3D.Normalize;
          WorldRotate[OverlayContent.Mouse.Drag.Update] =
            MouseAt3D.AngleBetween(MouseAt3D[OverlayContent.Mouse.Drag.In]) *
            WorldRotate[OverlayContent.Mouse.Drag.In];
        }
        { // pan is very easy.
          var UseMouseAt = MouseAt * -1d;
          OverlayContent.Mouse.HoldTimeout = TimeSpan.FromMilliseconds(300);
          Pan[OverlayContent.Mouse.Hold.Update] =
            Pan[OverlayContent.Mouse.Hold.In] + (UseMouseAt - UseMouseAt[OverlayContent.Mouse.Hold.In]);
        }
        { // zoom is easy.
          Zoom[OverlayContent.Mouse.Wheel] =
            (Zoom + ((DoubleBl) OverlayContent.Mouse.Wheel.Delta) * .1 / 120d).Clamp(.1, 10);
        }
      }


      // world matrix specifies where a render object will go in the world. Just set it to the default for now.

      int DIM;
      {
        var canvasD = new CanvasBl() {
          Width = 400d,
        };
        var dimSlider = new SliderBl(canvasD) {
          Minimum = 5,
          Maximum = 60,
          Value = 20,
          Width = canvasD.Width,
          LeftTop = 0d,
        };
        var button = new ButtonBl(canvasD) {
          LeftTop = dimSlider.LeftBottom,
          Content = "Close at DIM = " + ((IntBl)dimSlider.Value).ToStringBl(),
        };
        canvasD.Height = dimSlider.Height + button.Height;
        var dlg = new WindowBl() {
          Content = canvasD,
          SizeToContent = SizeToContent.WidthAndHeight,
          ShowInTaskbar = false,
        };
        dlg.Close[button.Click1].Apply();

        //button.Click = () => dlg.CurrentValue.Close();

        dlg.ShowDialog.Apply();
        DIM = (int)dimSlider.Value.CurrentValue;
      }


      // represents where our eye is in the world.
      Double3Bl WorldCenter = new Double3Bl(0, 0, 0);

      // Configure a WPF perspective camera.

      //Matrix4Bl CameraMatrix;

      Double3Bl CameraPosition = WorldCenter + new Double3Bl(0, 0, -8 /** (1d / Zoom)*/);
      PerspectiveCameraCl Camera = new PerspectiveCameraCl() {
        Position = CameraPosition,
        Direction = { Look = WorldCenter },
        FieldOfView = .1.PI().Degrees,
      };
      //CameraMatrix = Camera.Matrix;
      CameraPosition = Camera.Position;


      // create a new device in which to hold rendering information
      // this will actually cause rendering to occur in a WPF host. 
      var lightA = new SpotLightBl() {
        Direction = new Double3Bl(0, 0, 1d).Normalize,
        Color = Colors.Pink,
        Position = new Double3Bl(0, 0, -10),
        InnerConeAngle = 2.Degrees(),
        OuterConeAngle = 4.Degrees(),
      };
      var lightB = new DirectionalLightBl() {
        Direction = new Double3Bl(-.5, -.5, 10d).Normalize,
        Color = Colors.White,
      };
      var light = lightA + lightB;
      var diffuse = new DiffuseMaterialCl() { Knob = .4, Ambient = { Knob = .4 } };
      var Cubish = new CubeMesh();


      {
        var SIZE = (1d / ((double)DIM - 0d));
        Double2Bl Slope;
        Double2Bl NewStart;
        {
          BoolBl DoSwap = (CutEnd.Y < CutStart.Y);
          NewStart = DoSwap.Condition(CutEnd, CutStart);
          var NewEnd = DoSwap.Condition(CutStart, CutEnd);
          Slope = (NewEnd - NewStart).Normalize;
        }
        Slope = (Slope * -1d); 
        NewStart = NewStart * 2d - 1d;
        var AxisSlope = Slope.XY();
        Matrix4Bl ProjectView = (Camera.Project * Camera.View);
        Matrix4Bl ZoomPanWorld = 
          Matrix4Bl.MakeScale(Zoom, new Double3Bl(Pan.XY(), -2)) *
          Matrix4Bl.MakeTranslate(Pan.AddZ(0)) *
          WorldRotate.Matrix;

        Device.Render(Cubish, DIM * DIM * DIM, (jdx, Entry, vertex) => {
          IntBl x = (jdx % (DIM));
          IntBl y = (jdx / (DIM)) % DIM;
          IntBl z = (jdx / (DIM)) / DIM;
          Double3Bl xyz = new Double3Bl(x, y, z);
          var Translate = Matrix4Bl.MakeTranslate(xyz.PerVertex() * (SIZE * 2));
          Matrix4Bl ScaleDown = Matrix4Bl.MakeScale(SIZE, -1d);


          Matrix4Bl CutMatrix = Matrix4Bl.Identity;
          QuaternionBl CutRotate = QuaternionBl.Identity;
          {
            {
              var CutPos = (AtCut.Matrix * Translate * ScaleDown).Transform(0d.Bl().XXX());
              var X = NewStart.X - (CutPos.Y + NewStart.Y) / Slope.Y * Slope.X;
              var CutDir = (CutPos.X >= X).Condition(+1d.Bl(), -1d.Bl());
              {
                var p = new Double3Bl(AxisSlope.YX(), 0) * CutAngle * CutDir * -1d;
                CutMatrix = Matrix4Bl.MakeTranslate(AtCut.Inverse.Transform(p));
                {
                  var CutAngle0 = CutAngle.PI() * .25d * CutDir;

                  var CutRotateAxis = new Double3Bl(AxisSlope * new Double2Bl(-1, +1), 0d);
                  CutRotateAxis = AtCut.Inverse.Transform(CutRotateAxis);
                  CutRotate = (new QuaternionBl(CutRotateAxis, CutAngle0));
                }
                CutMatrix = CutMatrix * CutRotate.Matrix;
              }
            }
          }
          Double3Bl WorldPos;
          IntBl MatIndex = GetVoxels2(DIM).Table(jdx);
          ColorBl clr = MaterialColors.Table(MatIndex);
          DoubleBl TransferScale = 0d;

          //TransferScale = TransferScale + MaterialScales.Table(MatIndex);// IntBl.Table(MaterialScales, MatIndex);

          for (int i = 0; i < MaterialScales.Length; i++) {
            TransferScale = TransferScale + MaterialScales[i] * (i == MatIndex).Condition(1d, 0d);
          }

          //TransferScale = TransferScale.PerVertex();
          {
            var Total = ProjectView * ZoomPanWorld * CutMatrix * Translate * ScaleDown;
            Total = Total * Matrix4Bl.MakeScale(TransferScale);
            Double4Bl pos = Total.Transform(Entry.Position);
            vertex.Position = pos;
            WorldPos = (Double3Bl)pos;
          }
          // do not including any translation for normal!
          var normal = new Double3Bl(0.0f, 1.0f, 0.0f);
          normal = Entry.Normal;
          normal = (WorldRotate * CutRotate).Transform(normal);
          clr = diffuse.ApplyLights(light + new AmbientLightBl() { Color = Colors.White }).
            ApplyAt(WorldPos, normal, CameraPosition).
            ForColor(clr);
          clr = new ColorBl(clr.ScRGB, 1d); //TransferScale);
          vertex.Color = clr;
        });
      }
    }
    private Color[] GetVoxels(int DIM) {
      Color[] CubeColors = new Color[DIM * DIM * DIM];
      {
        var rand = new Random();
        Action<int, double, double, Func<Color, double, Color>> G = (Count, Min, Max, Fc) => {
          for (int i = 0; i < Count; i++) {
            // try to find a coordinate.
            int x = rand.Next(DIM);
            int y = rand.Next(DIM);
            int z = rand.Next(DIM);
            var sz = Min + (Max - Min) * rand.NextDouble();
            for (int xi = 0; true; xi++) {
              var dxi = ((double)xi) / ((double)DIM);
              if (dxi > sz) break;
              for (int yi = 0; true; yi++) {
                var dyi = ((double)yi) / ((double)DIM);
                if (dyi > sz) break;
                for (int zi = 0; true; zi++) {
                  var dzi = ((double)zi) / ((double)DIM);
                  if (dzi > sz) break;

                  var v = new Vector3D(dxi, dyi, dzi);
                  var length = 1d - v.Length / sz;
                  if (length <= 0) continue;
                  Action<int, int, int> F = (xj, yj, zj) => {
                    if (xj >= DIM || xj < 0) return;
                    if (yj >= DIM || yj < 0) return;
                    if (zj >= DIM || zj < 0) return;
                    var jdx = xj + yj * DIM + zj * DIM * DIM;
                    if (CubeColors[jdx] == null) CubeColors[jdx] = Color.FromScRgb(1, 0, 0, 0);
                    var clr = CubeColors[jdx];
                    clr = Fc(clr, length);
                    CubeColors[jdx] = clr;
                  };
                  F(x + xi, y + yi, z + zi);
                  F(x + xi, y + yi, z - zi);
                  F(x + xi, y - yi, z + zi);
                  F(x + xi, y - yi, z - zi);

                  F(x - xi, y + yi, z + zi);
                  F(x - xi, y + yi, z - zi);
                  F(x - xi, y - yi, z + zi);
                  F(x - xi, y - yi, z - zi);
                }
              }
            }
          };
        };
        G(50, .03, .15, (clr, len) => {
          clr.ScB = (float)len;
          return clr;
        });
        G(10, .1, .2, (clr, len) => {
          var total = len + clr.ScB;
          clr.ScG = (float)(len / total);
          return clr;
        });
        for (int xi = 0; xi < DIM; xi++) {
          for (int yi = 0; yi < DIM; yi++) {
            for (int zi = 0; zi < DIM; zi++) {
              var jdx = xi + yi * DIM + zi * DIM * DIM;
              var clr = CubeColors[jdx];
              if (clr == null) CubeColors[jdx] = Colors.Red;
              else {
                var total = Math.Min(clr.ScB + clr.ScG, 1d);
                clr.ScR = (float)(1d - total);
                CubeColors[jdx] = clr;
              }
            }
          }
        }
      }

      return CubeColors;
    }
    private IntBl[] GetVoxels2(int DIM) {
      IntBl[] CubeColors = new IntBl[DIM * DIM * DIM];
      for (int i = 0; i < CubeColors.Length; i++) CubeColors[i] = IntBl.Default;
      {
        var rand = new Random();
        Action<int, double, double, Func<IntBl, double, IntBl>> G = (Count, Min, Max, Fc) => {
          for (int i = 0; i < Count; i++) {
            // try to find a coordinate.
            int x = rand.Next(DIM);
            int y = rand.Next(DIM);
            int z = rand.Next(DIM);
            var sz = Min + (Max - Min) * rand.NextDouble();
            for (int xi = 0; true; xi++) {
              var dxi = ((double)xi) / ((double)DIM);
              if (dxi > sz) break;
              for (int yi = 0; true; yi++) {
                var dyi = ((double)yi) / ((double)DIM);
                if (dyi > sz) break;
                for (int zi = 0; true; zi++) {
                  var dzi = ((double)zi) / ((double)DIM);
                  if (dzi > sz) break;

                  var v = new Vector3D(dxi, dyi, dzi);
                  var length = 1d - v.Length / sz;
                  if (length <= 0) continue;
                  Action<int, int, int> F = (xj, yj, zj) => {
                    if (xj >= DIM || xj < 0) return;
                    if (yj >= DIM || yj < 0) return;
                    if (zj >= DIM || zj < 0) return;
                    var jdx = xj + yj * DIM + zj * DIM * DIM;
                    var clr = CubeColors[jdx];
                    clr = Fc(clr, length);
                    CubeColors[jdx] = clr;
                  };
                  F(x + xi, y + yi, z + zi);
                  F(x + xi, y + yi, z - zi);
                  F(x + xi, y - yi, z + zi);
                  F(x + xi, y - yi, z - zi);

                  F(x - xi, y + yi, z + zi);
                  F(x - xi, y + yi, z - zi);
                  F(x - xi, y - yi, z + zi);
                  F(x - xi, y - yi, z - zi);
                }
              }
            }
          };
        };
        G(5 , .2, .4, (clr, len) => 1);
        G(10, .1, .2, (clr, len) => 2);
        G(50, .03, .15, (clr, len) => 3);
        G(50, .03, .15, (clr, len) => 4);
      }
      return CubeColors;
    }
    public static readonly ColorBl[] MaterialColors = new ColorBl[] {
      Colors.Wheat, 
      Colors.Orange,
      Colors.DarkOrange,
      Colors.Salmon,
      Colors.Purple,
    };
  }
}

